#include "SocketProtocoloPlano.h"
#include "../utils/UtilString.h"

#define MAX_MESSAGE_SIZE sizeof(unsigned long int)

SocketProtocoloPlano::SocketProtocoloPlano() {

}
SocketProtocoloPlano::SocketProtocoloPlano(int fd):Socket(fd){
	struct sockaddr_storage addr;
	socklen_t len;
	int port;

	getpeername(fd, (struct sockaddr*)&addr,&len);
	char ipstr[INET6_ADDRSTRLEN];


	if (addr.ss_family == AF_INET) {
	    struct sockaddr_in *s = (struct sockaddr_in *)&addr;
	    port = ntohs(s->sin_port);
	    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
	} else { // AF_INET6
	    struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
	    port = ntohs(s->sin6_port);
	    inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
	}

	this->ownerIp = ipstr;
}

int SocketProtocoloPlano::send(const std::string& stream){
	unsigned long int tamanio = stream.size();

	std::string tamanioString =UtilString::intToStringFixed(tamanio,MAX_MESSAGE_SIZE);

	int error = this->send(tamanioString.c_str(),MAX_MESSAGE_SIZE);

	if (error == SOCKET_ERROR)
	{
		return SOCKET_ERROR;
	}

	return (this->send(stream.c_str(), tamanio));
}

const std::string SocketProtocoloPlano::getOwnerIp() const{
	return ownerIp;
}

int SocketProtocoloPlano::send(const char* stream, int size){
	int bytesMandados =  0, bytesTotales = 0;

	while (bytesTotales < size){
		bytesMandados = ::send(this->fd, stream + bytesTotales, size - bytesTotales, 0);

		if (bytesMandados == SOCKET_ERROR)
		{
			return SOCKET_ERROR;
		}

		bytesTotales += bytesMandados;
	}

	return SOCKET_EXITO;
}


int SocketProtocoloPlano::receive(char* stream, int size){
	int bytesRecibidos = 0, bytesTotales = 0;

	while (bytesTotales < size){
		bytesRecibidos = ::recv(this->fd, stream + bytesTotales, size - bytesTotales, 0);

		if (bytesRecibidos == SOCKET_ERROR)
		{
			return SOCKET_ERROR;
		}

		bytesTotales += bytesRecibidos;
	}

	return SOCKET_EXITO;
}


int SocketProtocoloPlano::receive(std::string& stream){
	char tamanio[MAX_MESSAGE_SIZE];
	memset(&tamanio,0,MAX_MESSAGE_SIZE);
	tamanio[0]='\0';
	int error = this->receive(tamanio, MAX_MESSAGE_SIZE);

	if (error == SOCKET_ERROR)
	{
		return SOCKET_ERROR;
	}

	std::string longitud = tamanio;
	unsigned long int tamanioAux=UtilString::stringToInt(longitud);

	char* mensaje = new char[tamanioAux + 1];
	int resultado = this->receive(mensaje, tamanioAux);

	if (resultado == SOCKET_ERROR)
	{
		return SOCKET_ERROR;
	}

	mensaje[tamanioAux] = '\0';
	stream = mensaje;

	delete[] mensaje;

	return resultado;
}


SocketProtocoloPlano* SocketProtocoloPlano::accept(){
	int new_fd = Socket::accept();

	if (new_fd > 0){
		SocketProtocoloPlano* nuevoSocket = new SocketProtocoloPlano(new_fd);
		return nuevoSocket;
	} else {
		return NULL;
	}
}
